import logging
import os
from dataclasses import dataclass, field, fields
from typing import Any, Optional

from langchain_core.runnables import RunnableConfig

from src.config.report_style import ReportStyle
logger = logging.getLogger(__name__)


# 融合多处的配置信息，形成Configuration配置实例，产生的方法是通过类函数from_runnable_config，可以认为是一个工厂函数
@dataclass(kw_only=True)
class Configuration:
    """The configurable fields."""
    #这里暂时剔除了resources，因为暂时用不到rag
    max_plan_iterations: int = 1  # Maximum number of plan iterations
    max_step_num: int = 3  # Maximum number of steps in a plan
    max_search_results: int = 3  # Maximum number of search results
    mcp_settings: dict = None  # MCP settings, including dynamic loaded tools
    report_style: str = ReportStyle.ACADEMIC.value  # Report style
    enable_deep_thinking: bool = False  # Whether to enable deep thinking


    # 可以认为是一个工厂方法，返回一个Configuration实例，该方法融合环境变量和config的配置，形成当前的配置信息
    @classmethod
    def from_runnable_config(
        cls, config: Optional[RunnableConfig] = None
    ) -> "Configuration":
        """Create a Configuration instance from a RunnableConfig."""

        # 这里的括号是分组运算符，将括号内的所有内容视为一个完整的表达式，即使它跨越多行
        configurable = (
            # 提取config中的configurable字段信息
            config["configurable"] if config and "configurable" in config else {}
        )
        # values 就是该类的各个属性与其对应值的键值对
        values: dict[str, Any] = {

            # 如果环境变量中含有当前字段f.name的配置，则返回环境变量中的配置值
            # 如果环境变量没有配置，但是configurable中有该字段的配置，则使用configurable中的配置
            # 如果两处都没有该字段的配置，则返回none
            f.name: os.environ.get(f.name.upper(), configurable.get(f.name))
            for f in fields(cls)
            if f.init  # 默认的属性init都为True,表示需要初始化，init==True的字段会出现在构造函数中
        }

        # ** 操作符将字典解包为关键字参数，比如有字典{k1：v1，k2，v2},下面代码会是cls(k1=v1,k2=v2)
        # 因为kw_only=True 要求必须使用关键字参数创建实例
        return cls(**{k: v for k, v in values.items() if v})